package com.qiaofang.applet.service.property.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.context.QfContext;
import com.qiaofang.applet.common.context.QfContextHolder;
import com.qiaofang.applet.common.util.RedisKeyUtil;
import com.qiaofang.applet.common.util.RedisUtil;
import com.qiaofang.applet.service.property.domain.Area;
import com.qiaofang.applet.service.property.domain.District;
import com.qiaofang.applet.service.property.repository.DistrictRepository;
import com.qiaofang.applet.service.property.service.AreaService;
import com.qiaofang.applet.service.property.service.DistrictService;
import com.qiaofang.applet.service.property.service.dto.AreaDto;
import com.qiaofang.applet.service.property.service.dto.DistrictAreaDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DistrictServiceImpl extends MongoBaseService<District, String> implements DistrictService {

    private final DistrictRepository repository;

    @Autowired
    AreaService areaService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    public DistrictServiceImpl(DistrictRepository repository) {
        super(repository);
        this.repository = repository;
    }

    @Override
    public District findByDistrictUuidAndCompanyUuid(String districtUuid, String companyUuid) {
        return repository.findByDistrictUuidAndCompanyUuid(districtUuid, companyUuid);
    }

    @Override
    public List<District> findAllByCityCode(String cityCode) {
        QfContext qfContext = QfContextHolder.getContext();
        String corporationCode = qfContext.getCorporationCode();
        List<District> districtList = repository.findAllByCityCodeAndCorporationCode(cityCode, corporationCode);
        districtList = districtList.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(
                        Comparator.comparing(
                                District::getDistrictUuid))), ArrayList::new));
        return districtList;
    }

    @Override
    public List<District> findAllByCityCode(String corporationCode, String cityCode) {
        return repository.findAllByCityCodeAndCorporationCode(cityCode, corporationCode);
    }

    @Override
    public List<DistrictAreaDto> findAllDistrictAndArea(String corporationCode, String cityCode) {
        String districtAndAreaKey = RedisKeyUtil.getDistrictAndAreaKey(corporationCode, cityCode);
        Object obj = redisUtil.get(districtAndAreaKey);
        if (obj != null) {
            return transBean2List(obj);
        }
        List<District> districtList = findAllByCityCode(corporationCode, cityCode);
        //去除重复区域
        districtList = districtList.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(
                        Comparator.comparing(
                                District::getDistrictUuid))), ArrayList::new));

        List<Area> areaList = areaService.findAllByCityCode(corporationCode, cityCode);
        //去除重复商圈
        areaList = areaList.stream().collect(Collectors.collectingAndThen(
                Collectors.toCollection(() -> new TreeSet<>(
                        Comparator.comparing(
                                Area::getAreaUuid))), ArrayList::new));
        Map<String, List<Area>> areaMap = Optional.ofNullable(areaList)
                .orElseGet(Lists::newArrayList).stream().collect(Collectors.groupingBy(Area::getDistrictUuid));
        List<DistrictAreaDto> list = Optional.ofNullable(districtList).orElseGet(Lists::newArrayList).stream().map(item -> {
            DistrictAreaDto dto = new DistrictAreaDto();
            dto.setDistrictUuid(item.getDistrictUuid());
            dto.setDistrictName(item.getDistrictName());
            dto.setAreaDtoList(convert(areaMap.get(item.getDistrictUuid())));
            return dto;
        }).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(list)) {
            redisUtil.setToDayEnd(districtAndAreaKey, list);
        }
        return list;
    }

    @Override
    public Map<String, String> getAllDistrictMap(String corporationCode) {
        String districtMapKey = RedisKeyUtil.getDistrictMapKey(corporationCode);
        Object obj = redisUtil.get(districtMapKey);
        if (obj != null) {
            return (Map<String, String>) obj;
        }
        Map<String, String> districtMap = new HashMap<>();
        List<District> list = repository.findAllByCorporationCode(corporationCode);
        if (!CollectionUtils.isEmpty(list)){
            for (District district : list) {
                districtMap.put(district.getDistrictUuid(), district.getDistrictName());
            }
            redisTemplate.opsForHash().putAll(districtMapKey, districtMap);
            redisTemplate.expire(districtMapKey, 86400 - DateUtils.getFragmentInSeconds(Calendar.getInstance(), Calendar.DATE), TimeUnit.SECONDS);
        }
        return districtMap;
    }

    private List<DistrictAreaDto> transBean2List(Object obj) {
        return JSONObject.parseArray(JSONObject.toJSONString(obj), DistrictAreaDto.class);
    }

    /**
     * 对象转换
     *
     * @param list
     * @return
     */
    private List<AreaDto> convert(List<Area> list) {
        return Optional.ofNullable(list).orElseGet(Lists::newArrayList).stream().map(item -> {
            AreaDto dto = new AreaDto();
            BeanUtils.copyProperties(item, dto);
            return dto;
        }).collect(Collectors.toList());
    }
}

